package cn.tradewin.pmp.translators;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParsePosition;

import org.apache.tapestry5.Field;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.ValidationException;
import org.apache.tapestry5.internal.translator.AbstractTranslator;
import org.apache.tapestry5.ioc.services.ThreadLocale;
import org.apache.tapestry5.services.FormSupport;

public class MoneyTranslator extends AbstractTranslator<BigDecimal> {

	private final int maxDecimalPlaces;
	private final ThreadLocale threadLocale;
	private ParsePosition parsePosition;

	public MoneyTranslator(String name, int maxDecimalPlaces,
			ThreadLocale threadLocale) {
		super(name, BigDecimal.class, "money-format-ecxeption");
		this.maxDecimalPlaces = maxDecimalPlaces;
		this.threadLocale = threadLocale;
	}

	@Override
	public String toClient(BigDecimal value) {
		DecimalFormat decimalFormat = (DecimalFormat) NumberFormat
				.getCurrencyInstance(threadLocale.getLocale());
		DecimalFormatSymbols decimalFormatSymbols = decimalFormat
				.getDecimalFormatSymbols();
		decimalFormatSymbols.setCurrencySymbol("");
		decimalFormat.setDecimalFormatSymbols(decimalFormatSymbols);
		return decimalFormat.format(value).trim();
	}

	@Override
	public BigDecimal parseClient(Field field, String clientValue,
			String message) throws ValidationException {
		if (clientValue == null) {
			return null;
		} else {
			BigDecimal money = parseMoney(clientValue.trim(), message);
			if (money.scale() > this.maxDecimalPlaces) {
				throw new ValidationException(message);
			}
			return money;
		}
	}

	@Override
	public void render(Field field, String message, MarkupWriter writer,
			FormSupport formSupport) {
		// TODO Auto-generated method stub

	}

	private BigDecimal parseMoney(String clientValue, String message) throws ValidationException {
		DecimalFormat numberFormat = (DecimalFormat) NumberFormat.getInstance(threadLocale.getLocale());
		numberFormat.setParseBigDecimal(true);
		// ...in the format of the client locale (eg. 12,345.67 or 12345.67 or
		// -12,345.67 or -12 345,67)
		numberFormat.setNegativePrefix("-");
		numberFormat.setNegativeSuffix("");
		parsePosition.setIndex(0);
		BigDecimal bigDecimal = (BigDecimal) numberFormat.parse(clientValue,parsePosition);
		if (parsePosition.getIndex() == clientValue.length()
				&& bigDecimal != null) {
			return bigDecimal;
		}

		// ...with trailing negative sign (eg. 12,345.67-)
		numberFormat.setNegativePrefix("");
		numberFormat.setNegativeSuffix("-");
		parsePosition.setIndex(0);
		bigDecimal = (BigDecimal) numberFormat
				.parse(clientValue, parsePosition);

		if (parsePosition.getIndex() == clientValue.length()
				&& bigDecimal != null) {
			return bigDecimal;
		}

		// ...with brackets for negative (eg. (12,345.67))

		numberFormat.setNegativePrefix("(");
		numberFormat.setNegativeSuffix(")");
		parsePosition.setIndex(0);
		bigDecimal = (BigDecimal) numberFormat
				.parse(clientValue, parsePosition);

		if (parsePosition.getIndex() == clientValue.length()
				&& bigDecimal != null) {
			return bigDecimal;
		}

		throw new ValidationException(message);
	}

}
